using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Acms.DataControls
{
    public abstract class BaseDataSource<Collection, Item> : DataSourceControl
        where Collection : Acms.Bll.BaseCollection<Item>, new()
        where Item : Acms.Bll.BaseItem, new()
    {
        public BaseDataSource()
        {
        }

        private BaseDataSourceView<Collection, Item> _view;
        protected BaseDataSourceView<Collection, Item> View
        {
            get
            {
                if (_view == null)
                {
                    _view = new BaseDataSourceView<Collection, Item>(this);
                    //_view.GetData += new BaseDataSourceViewGetDataEventHandler<Collection>(_view_GetData);
                    _view.GetData += new EventHandler<BaseDataSourceViewGetDataEventArgs<Collection,Item>>(_view_GetData);
                }
                return _view;
            }
        }

        #region IDataSource Members

        public event EventHandler DataSourceChanged;

        protected override DataSourceView GetView(string viewName)
        {
            return View;
        }

        public event EventHandler<BaseDataSourceViewGetDataEventArgs<Collection, Item>> GetData;

        //public event BaseDataSourceViewGetDataEventHandler<Collection, Item> GetData;
        void _view_GetData(object sender, BaseDataSourceViewGetDataEventArgs<Collection, Item> e)
        {
            if (GetData != null)
            {
                GetData(sender, e);
            }
        }

        protected override ICollection GetViewNames()
        {
            return new string[] { "default" };
        }

        #endregion

        internal void OnDataSourceChanged()
        {
            if (DataSourceChanged != null)
            {
                DataSourceChanged(this, EventArgs.Empty);
            }
        }

        internal System.Web.TraceContext Trace
        {
            get
            {
                return base.Context.Trace;
            }
        }

        public bool EnablePaging
        {
            get { return View.EnablePaging; }
            set { View.EnablePaging = value; }
        }
	
    }

    public class BaseDataSourceView<Collection, Item> : DataSourceView
        where Collection : Acms.Bll.BaseCollection<Item>, new()
        where Item : Acms.Bll.BaseItem, new()
    {
        internal BaseDataSourceView(BaseDataSource<Collection, Item> dataSource)
            : base(dataSource, "default")
        {
            _dataSource = dataSource;
        }

        internal event EventHandler<BaseDataSourceViewGetDataEventArgs<Collection, Item>> GetData;

        private Collection _data;
        protected Collection Data
        {
            get
            {
                if (_data == null && GetData != null)
                {
                    BaseDataSourceViewGetDataEventArgs<Collection, Item> args = new BaseDataSourceViewGetDataEventArgs<Collection, Item>();
                    GetData(this._dataSource, args);
                    _data = args.Data;
                }
                return _data;
            }
        }

        private BaseDataSource<Collection,Item> _dataSource;

        protected override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
        {
            return Data;
        }

        private Item FindItemFromKeys(IDictionary keys)
        {
            foreach (Item item in Data)
            {
                bool foundItem = true;
                foreach (string key in keys.Keys)
                {
                    if (item.GetType().GetProperty(key) != null)
                    {
                        if (item.GetType().GetProperty(key).GetValue(item, new object[0]) == null && keys[key] != null)
                        {
                            foundItem = false;
                            break;
                        }
                        else if (item.GetType().GetProperty(key).GetValue(item, new object[0]) != null && keys[key] == null)
                        {
                            foundItem = false;
                            break;
                        }
                        else if (!item.GetType().GetProperty(key).GetValue(item, new object[0]).Equals(keys[key]))
                        {
                            foundItem = false;
                            break;
                        }
                    }
                    else if (item.GetType().GetField(key) != null)
                    {
                        if (item.GetType().GetField(key).GetValue(item) == null && keys[key] != null)
                        {
                            foundItem = false;
                            break;
                        }
                        else if (item.GetType().GetField(key).GetValue(item) != null && keys[key] == null)
                        {
                            foundItem = false;
                            break;
                        }
                        else if (!item.GetType().GetField(key).GetValue(item).Equals(keys[key]))
                        {
                            foundItem = false;
                            break;
                        }
                    }
                    else
                    {
                        throw new ApplicationException(string.Format("Could not find property or field for key '{0}' in object of type '{1}'", key, item.GetType().ToString()));
                    }
                }
                if (foundItem)
                {
                    return item;
                }
            }
            return null;
        }

        protected override int ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues)
        {
            _dataSource.Trace.Write("ExecuteUpdate");
            Item item = FindItemFromKeys(keys);
            if (item != null)
            {
                foreach (string key in values.Keys)
                {
                    if ((oldValues[key] == null && values[key] != null) ||
                        (oldValues[key] != null && values[key] == null) ||
                        !oldValues[key].Equals(values[key]))
                    {
                        if (item.GetType().GetProperty(key) != null)
                        {
                            item.GetType().GetProperty(key).SetValue(item, values[key], new object[0]);
                        }
                        else if (item.GetType().GetField(key) != null)
                        {
                            item.GetType().GetField(key).SetValue(item, values[key]);
                        }
                        else
                        {
                            throw new ApplicationException(string.Format("Could not find property or field for key '{0}' in object of type '{1}'", key, item.GetType().ToString()));
                        }
                    }
                }
                Data.SaveChanges();
                return 1;
            }
            else
            {
                return 0;
            }

        }

        protected override int ExecuteInsert(IDictionary values)
        {
            Item item = Data.Add();
            foreach (string key in values.Keys)
            {
                if (item.GetType().GetProperty(key) != null)
                {
                    item.GetType().GetProperty(key).SetValue(item, values[key], new object[0]);
                }
                else if (item.GetType().GetField(key) != null)
                {
                    item.GetType().GetField(key).SetValue(item, values[key]);
                }
                else
                {
                    throw new ApplicationException(string.Format("Could not find property or field for key '{0}' in object of type '{1}'", key, item.GetType().ToString()));
                }
            }
            Data.SaveChanges();
            return 1;
        }

        protected override int ExecuteDelete(IDictionary keys, IDictionary oldValues)
        {
            Item i = FindItemFromKeys(keys);
            if (i != null)
            {
                Data.Delete(i);
                Data.SaveChanges();
                return 1;
            }
            else
            {
                return 0;
            }

        }

        private bool _enablePaging;

        public bool EnablePaging
        {
            get { return _enablePaging; }
            set { _enablePaging = value; }
        }
	

    }

    //public delegate void BaseDataSourceViewGetDataEventHandler<Collection, Item>(object sender, BaseDataSourceViewGetDataEventArgs<Collection, Item> e);

    public class BaseDataSourceViewGetDataEventArgs<Collection, Item> : System.EventArgs
        where Collection : Acms.Bll.BaseCollection<Item>, new() 
        where Item : Acms.Bll.BaseItem, new()
    {
        public BaseDataSourceViewGetDataEventArgs()
        {
        }

        private Collection _data;
        public void SetData(Collection data)
        {
            _data = data;
        }
        
        public void SetData(Item data)
        {
            if (_data == null)
            {
                _data = new Collection();
                _data.Add(data);
            }
            else
            {
                throw new ApplicationException("Data has alreay been set");
            }
        }

        internal Collection Data
        {
            get
            {
                return _data;
            }
        }
    }

    //public delegate void BaseDataSourceViewSaveDataEventHandler<Collection>(object sender, BaseDataSourceViewSaveDataEventArgs<Collection> e);

    public class BaseDataSourceViewSaveDataEventArgs<Collection> : System.EventArgs
    {
        public BaseDataSourceViewSaveDataEventArgs(Collection data)
        {
            _data = data;
        }

        private Collection _data;
        public Collection Data
        {
            get
            {
                return _data;
            }
        }
    }
}
